﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Web;
using Microsoft.Office.Interop.Excel;
using HitachiService.DBAccess;
using HitachiService;
using HitachiLib.Utils;

namespace HitachiService.Office
{
    public class Node : IComparable
    {
        public static Dictionary<int, Node> project_map = new Dictionary<int, Node>();
        public static Node GetByID(int id)
        {
            if (project_map.ContainsKey(id))
                return project_map[id];
            return null;
        }

        public String Name;
        public BaseData Data;
        public List<Node> Children = new List<Node>();
        public Node parent;
        public DateTime adjusted_date;

        public Node Parent
        {
            get { return parent; }
            set
            {
                parent = value;
                parent.Children.Add(this);
            }
        }

        public Node(BaseData p)
        {
            if (!project_map.ContainsKey(p.ID))
                project_map.Add(p.ID, this);
            Data = p;
        }

        public int CompareTo(object obj)
        {
            Node n = obj as Node;
            DateTime other = n.adjusted_date;
            DateTime self = adjusted_date;
            return (self.CompareTo(other));
        }
    }

    public class ScheduleExporter
    {
        private ProjectData zoon_data;
        private ProjectData server_data;
        private ProjectData line_data;
        private Application app;
        private Node line_node;
        private bool loaded;
        private DateTime begin_date;
        private DateTime end_date;
        private List<Node> sorted_nodes = new List<Node>();
        private int nodes_index = 0;

        private DateTime current_day;
        private DateTime current_time;


        public ScheduleExporter(int week_id, int line_id)
        {
            begin_date = DateUtils.BaseServiceDate();
            begin_date = begin_date.AddDays(week_id * 7);
            end_date = begin_date.AddDays(7);

            loaded = LoadData(week_id, line_id);
        }

        private bool AdjustTime(Node node)
        {
            ScheduleData s = node.Data as ScheduleData;
            DateTime dt = DateUtils.GetDate(s.ActionDate, s.ActionTime);
            if (s.ActionType == DateUtils.HalfMonth)
            {
                while (dt.CompareTo(begin_date) < 0)
                {
                    dt = dt.AddDays(14);
                }
                while (dt.CompareTo(end_date) >= 7)
                {
                    dt = dt.AddDays(-14);
                }
                double days = dt.Subtract(begin_date).TotalDays;
                if (days >= 7)
                {
                    return false;
                }
                node.adjusted_date = dt;
                return true;
            }
            else
            {
                double days = dt.Subtract(begin_date).TotalDays;
                if (days >= 0 && days < 7)
                {
                    node.adjusted_date = dt;
                    return true;
                }
                return false;
            }
        }

        private bool LoadData(int week_id, int line_id)
        {
            // Load Route info
            line_data = ProjectAccess.GetProjectById(line_id);
            if (line_data == null || line_data.Level != 10)
                return false;
            line_node = new Node(line_data);
            
            server_data = ProjectAccess.GetProjectById(line_data.ParentID);
            if (server_data == null)
                return false;
            Node server_node = new Node(server_data);
            line_node.Parent = server_node;

            zoon_data = ProjectAccess.GetProjectById(server_data.ParentID);
            if (zoon_data == null)
                return false;
            Node zoon_node = new Node(zoon_data);
            server_node.Parent = zoon_node;

            // Load Projects
            List<ProjectData> projects = ProjectAccess.GetProjectsByParentId(line_id);
            foreach (ProjectData p in projects)
            {
                Node p_node = new Node(p);
                p_node.Parent = line_node;
            }
            List<ScheduleData> schedules = ScheduleAccess.GetSchedulesByParentProject(line_id);
            foreach (ScheduleData s in schedules)
            {
                Node s_node = new Node(s);
                if (AdjustTime(s_node))
                {
                    Node p_node = Node.GetByID(s.ProjectId);
                    s_node.parent = p_node;
                    sorted_nodes.Add(s_node);
                }
            }
            sorted_nodes.Sort();

            // Sort Schedule
            return true;
        }

        public String Export()
        {
            try
            {
                if (!loaded)
                    return "ERR:00001";
                String file_root = System.Configuration.ConfigurationManager.AppSettings["localFileRoot"];
                String remoteFileRoot = System.Configuration.ConfigurationManager.AppSettings["remoteFileRoot"];
                String template_file_path = file_root + @"Template.xls";
                DateTime now = DateTime.Now;
                if (!File.Exists(template_file_path))
                {
                    return template_file_path;
                }

                String now_str = "" + (now.Year * 10000 + now.Month * 100 + now.Day) + "_" + (now.Hour * 10000 + now.Minute * 100 + now.Second);
                String filename = zoon_data.Name + "_" + server_data.Name + "_" + line_data.Name + "_" + now_str + ".xls";
                String result_path = file_root + filename;
                app = new ApplicationClass();

                File.Copy(template_file_path, result_path, true);
                Workbook wb = app.Workbooks.Open(result_path);

                int current_line = 5;
                nodes_index = 0;
                current_line = PrintWeek(sorted_nodes, current_line);
                wb.Save();
                wb.Close();
                app.Quit();
                return remoteFileRoot + filename;
            }
            catch (Exception e)
            {
                return e.Message + "|" + e.StackTrace;
            }
        }

        private int PrintWeek(List<Node> sorted_schedule, int current_line)
        {
            int start_line;
            Range r;

            start_line = current_line;
            current_day = begin_date;

            current_line = PrintDay(sorted_schedule, current_line);
            r = app.get_Range("A" + start_line, "A" + (current_line - 1));
            r.Merge();
            r.Value2 = "一";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_day = current_day.AddDays(1);
            start_line = current_line;
            current_line = PrintDay(sorted_schedule, current_line);
            r = app.get_Range("A" + start_line, "A" + (current_line - 1));
            r.Merge();
            r.Value2 = "二";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_day = current_day.AddDays(1);
            start_line = current_line;
            current_line = PrintDay(sorted_schedule, current_line);
            r = app.get_Range("A" + start_line, "A" + (current_line - 1));
            r.Merge();
            r.Value2 = "三";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_day = current_day.AddDays(1);
            start_line = current_line;
            current_line = PrintDay(sorted_schedule, current_line);
            r = app.get_Range("A" + start_line, "A" + (current_line - 1));
            r.Merge();
            r.Value2 = "四";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_day = current_day.AddDays(1);
            start_line = current_line;
            current_line = PrintDay(sorted_schedule, current_line);
            r = app.get_Range("A" + start_line, "A" + (current_line - 1));
            r.Merge();
            r.Value2 = "五";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_day = current_day.AddDays(1);
            start_line = current_line;
            current_line = PrintDay(sorted_schedule, current_line);
            r = app.get_Range("A" + start_line, "A" + (current_line - 1));
            r.Merge();
            r.Value2 = "六";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_day = current_day.AddDays(1);
            start_line = current_line;
            current_line = PrintDay(sorted_schedule, current_line);
            r = app.get_Range("A" + start_line, "A" + (current_line - 1));
            r.Merge();
            r.Value2 = "日";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            r = app.get_Range("C5", "M" + (current_line - 1));
            r.Borders.LineStyle = XlLineStyle.xlDash;
            r = app.get_Range("A5", "M" + (current_line - 1));
            r.Borders.LineStyle = XlLineStyle.xlContinuous;
            return current_line;
        }

        private int PrintDay(List<Node> sorted_schedule, int current_line)
        {
            int start_line;
            Range r;

            current_time = current_day.AddHours(6);
            start_line = current_line;
            current_line = PrintTime(sorted_schedule, current_line);
            r = app.get_Range("B" + start_line, "B" + (current_line - 1));
            r.Merge();
            r.Value2 = "上午";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_time = current_day.AddHours(12);
            start_line = current_line;
            current_line = PrintTime(sorted_schedule, current_line);
            r = app.get_Range("B" + start_line, "B" + (current_line - 1));
            r.Merge();
            r.Value2 = "中午";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            current_time = current_day.AddHours(18);
            start_line = current_line;
            current_line = PrintTime(sorted_schedule, current_line);
            r = app.get_Range("B" + start_line, "B" + (current_line - 1));
            r.Merge();
            r.Value2 = "晚上";
            r.Borders.LineStyle = XlLineStyle.xlContinuous;

            return current_line;
        }
        private bool Quarter(ProjectData pd)
        {
            DateTime today = begin_date;
            DateTime target_date = DateUtils.GetDate(pd.ActionDate);
            DateTime next_date = DateUtils.GetNearest(target_date, DateUtils.ThreeMonth);
            TimeSpan ts = next_date.Subtract(today);
            int d = (int)ts.TotalDays;

            if (d < 7 && d > -7)
            {
                return true;
            }
            return false;
        }
        private int YearDiff(ProjectData pd)
        {
            DateTime today = begin_date;
            DateTime target_date = DateUtils.GetDate(pd.ActionDate);
            DateTime next_date = DateUtils.GetNearest(target_date, DateUtils.WholeYear);
            TimeSpan ts = next_date.Subtract(today);
            int d = (int)ts.TotalDays;
            return d;
        }
        private String AutoActionTypeStr(ProjectData pd, ScheduleData sd)
        {
            if (sd.ActionType == DateUtils.HalfMonth)
            {
                if (Quarter(pd))
                    return "季度";
                else
                    return "常规";
            }
            else
            {
                int diff = YearDiff(pd);
                if (diff < 45 && diff > -45)
                    return "全年";
                else
                    return "半年";
            }
        }

        private int PrintTime(List<Node> sorted_schedule, int current_line)
        {
            int start_line = current_line;
            while (nodes_index < sorted_nodes.Count)
            {
                Node s_node = sorted_nodes[nodes_index];
                if (s_node.adjusted_date.CompareTo(current_time) > 0)
                {
                    break;
                }
                nodes_index++;
                Node p_node = s_node.parent;
                ScheduleData s = s_node.Data as ScheduleData;
                ProjectData p = p_node.Data as ProjectData;

                app.Cells[current_line, 3] = p.CustomName;
                app.Cells[current_line, 4] = p.DevID;
                app.Cells[current_line, 5] = p.FloorType;
                app.Cells[current_line, 6] = AutoActionTypeStr(p, s);
                app.Cells[current_line, 7] = p.CustomType;
                app.Cells[current_line, 8] = p.ContractType;
                app.Cells[current_line, 9] = p.DevFloor;

                int date = p.ActionDate;
                DateTime dt = DateUtils.GetDate(date);
                app.Cells[current_line, 10] = dt.Month + "月" + dt.Day + "日";

                app.Cells[current_line, 11] = zoon_data.Name;
                app.Cells[current_line, 12] = server_data.Name;
                app.Cells[current_line, 13] = line_data.Name;

                current_line++;
            }
            if (current_line - start_line < 2)
                current_line = start_line + 2;
            return current_line;
        }
    }
}